﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;
using System.IO;
using Microsoft.DirectX;

namespace ParticleEditor
{
    public class Emitter
    {
        SGP.CSGP_Direct3D DX = SGP.CSGP_Direct3D.GetInstance();
        SGP.CSGP_TextureManager TM = SGP.CSGP_TextureManager.GetInstance();

        // public variables
        #region
        // BOOL
        public bool isLooping = true; // is the emitter looping

        // INT
        public int imageID; // current image number
        public int emitType; // type of emitter style (point, rectangle, circle, line)
        public int maxNumParticles = 100; // maximum number of particles on the screen
        public int activeCount; // how many particles are currently active / on the screen
        public int moveDirectionX1;
        public int moveDirectionY1;
        public int moveDirectionX2;
        public int moveDirectionY2;

        // FLOAT
        public float lineRotation; // rotation angle for the line emitter type
        public float startRotation = 10; // starting rotation angle
        public float endRotation; // ending rotation angle
        public float spawnRate = .01f; // how fast to spawn new particles
        public float spawnTimer; // timer to keep track of spawn rate
        public float maxParticleAge = 5.0f; // maximum time a particle will live
        public float moveDirectionXTimer = .2f;
        public float moveDirectionYTimer = .2f;

        // VECTOR2
        public Vector2 position; // position of the emitter
        public Vector2 startVelocity = new Vector2(100, 100); // starting velocity
        public Vector2 endVelocity = new Vector2(50, 50); // ending velocity
        public Vector2 startScale = new Vector2(.5f, .5f); // starting scale
        public Vector2 endScale = new Vector2(2, 2); // ending scale
        public Vector2 circleVector = new Vector2(0, 200); // radius used for the circle emitter type
        public Vector2 lineVector = new Vector2(0, 200); // radius used for the line emitter type

        // SIZE
        public Size emitterRectSize = new Size(100, 100); // size of the rectangle emitter type

        // COLOR
        public Color startColor = Color.Green; // starting color
        public Color endColor = Color.FromArgb(128, 255, 0, 255); // ending color

        // BITMAP
        public Bitmap particleImage;

        // STRING
        public string imageName; // name if the image being used
        string imageDirPath = System.IO.Path.GetFullPath(System.IO.Directory.GetCurrentDirectory() + "\\..\\..\\resource\\Graphics\\"); // default location to save images

        // LIST
        public List<Particle> particleList = new List<Particle>() { }; // list of particles
        #endregion

        // create random number Generator
        Random ness = new Random();

        // default ctor
        public Emitter() { ;}

        // save the current emitter to XML
        public void SaveToXML()
        {
            SaveFileDialog dlg = new SaveFileDialog();
            dlg.Filter = "All Files(*.*)|*.*|Particle Files(*.pxml)|*.pxml";
            dlg.FilterIndex = 2;
            dlg.DefaultExt = "pxml";

            dlg.InitialDirectory = System.IO.Path.GetFullPath(System.IO.Directory.GetCurrentDirectory() + "\\..\\..\\resource\\ParticleFiles");
            string imageDir = System.IO.Path.GetFullPath(System.IO.Directory.GetCurrentDirectory() + "\\..\\..\\resource\\Graphics");

            if (DialogResult.OK == dlg.ShowDialog())
            {
                string path = Path.GetDirectoryName(dlg.FileName);
                // root element
                XElement xERoot = new XElement("Particle_Editor");
                // root attributes
                XAttribute xALoop = new XAttribute("isLooping", isLooping); // is the emitter looping
                XAttribute xAParticleImage = new XAttribute("imageName", imageName); // the name of the image
                XAttribute xAImageDir = new XAttribute("imageDir", imageDir); // the directory the image is in

                xERoot.Add(xALoop);
                xERoot.Add(xAParticleImage);
                xERoot.Add(xAImageDir);

                // emitter element
                #region
                XElement xEEmitter = new XElement("Emitter");

                // emitter elements
                XElement xEType = new XElement("emitterType"); // emitter type
                // emitterType element attributes
                XAttribute xAType = new XAttribute("type", emitType);
                // add attribute to emitterType
                xEType.Add(xAType);

                XElement xENumParticles = new XElement("numParticles"); // number of particles
                // numParticles element attributes
                XAttribute xANumParticles = new XAttribute("particles", maxNumParticles);
                // add attribute to numParticles
                xENumParticles.Add(xANumParticles);

                XElement xELineRotation = new XElement("lineRotation"); // line rotation
                // lineRotation element attributes
                XAttribute xALineRotation = new XAttribute("rotation", lineRotation);
                // add attribute to lineRotation
                xELineRotation.Add(xALineRotation);

                XElement xESpawnRate = new XElement("spawnRate"); // spawnRate
                // spawnRate element attributes
                XAttribute xASpawnRate = new XAttribute("rate", spawnRate);
                // add attribute to spawnRate
                xESpawnRate.Add(xASpawnRate);

                XElement xEPosition = new XElement("position"); // position
                // position element attributes (x,y)
                XAttribute xAPositionX = new XAttribute("X", position.X); // x-axis
                XAttribute xAPositionY = new XAttribute("Y", position.Y); // y-axis
                //add attributes to position element
                xEPosition.Add(xAPositionX);
                xEPosition.Add(xAPositionY);

                XElement xECircleVector = new XElement("circleVector"); // circleVector radius
                //circleVector Attribute (x,y)
                XAttribute xACircleVectorX = new XAttribute("X", circleVector.X); // x-axis
                XAttribute xACircleVectorY = new XAttribute("Y", circleVector.Y); // y-axis
                // add attributes to circleVector element
                xECircleVector.Add(xACircleVectorX);
                xECircleVector.Add(xACircleVectorY);

                XElement xELineVector = new XElement("lineVector"); // lineVector length
                // lineVector attributes (x,y)
                XAttribute xALineVectorX = new XAttribute("X", lineVector.X); // x-axis
                XAttribute xALineVectorY = new XAttribute("Y", lineVector.Y); // y-axis
                // add attributes to the lineVector element
                xELineVector.Add(xALineVectorX);
                xELineVector.Add(xALineVectorY);

                XElement xEEmitterRectSize = new XElement("emitterRectSize"); // emitter rect size
                // emitterRectSize attributes (width, height)
                XAttribute xAEmitterRectSizeW = new XAttribute("Width", emitterRectSize.Width); // rectangle width
                XAttribute xAEmitterRectSizeH = new XAttribute("Height", emitterRectSize.Height); // rectangle height
                // add attributes to the emitterRectSize
                xEEmitterRectSize.Add(xAEmitterRectSizeW);
                xEEmitterRectSize.Add(xAEmitterRectSizeH);

                // add elements to the emitter element
                xEEmitter.Add(xEType);
                xEEmitter.Add(xENumParticles);
                xEEmitter.Add(xELineRotation);
                xEEmitter.Add(xESpawnRate);
                xEEmitter.Add(xEPosition);
                xEEmitter.Add(xECircleVector);
                xEEmitter.Add(xELineVector);
                xEEmitter.Add(xEEmitterRectSize);

                // add emitter element to the root element
                xERoot.Add(xEEmitter);
                #endregion

                // particle element
                #region
                XElement xEParticle = new XElement("Particle");

                // particle elements
                XElement xEMaxParticleAge = new XElement("maxParticleAge"); // maxe particle age
                // emitterType element attributes
                XAttribute xAMaxParticleAge = new XAttribute("age", maxParticleAge);
                // add attribute to emitterType
                xEMaxParticleAge.Add(xAMaxParticleAge);

                XElement xEStartRotation = new XElement("startRotation"); // starting rotation
                // emitterType element attributes
                XAttribute xAStartRotation = new XAttribute("rotation", startRotation);
                // add attribute to emitterType
                xEStartRotation.Add(xAStartRotation);

                XElement xEEndRotation = new XElement("endRotation"); // starting rotation
                // emitterType element attributes
                XAttribute xAEndRotation = new XAttribute("rotation", endRotation);
                // add attribute to emitterType
                xEEndRotation.Add(xAEndRotation);

                XElement xEStartColor = new XElement("startColor"); // starting color 
                // emitterType element attributes
                XAttribute xAStartColorA = new XAttribute("A", startColor.A);
                XAttribute xAStartColorR = new XAttribute("R", startColor.R);
                XAttribute xAStartColorG = new XAttribute("G", startColor.G);
                XAttribute xAStartColorB = new XAttribute("B", startColor.B);
                // add attribute to emitterType
                xEStartColor.Add(xAStartColorA);
                xEStartColor.Add(xAStartColorR);
                xEStartColor.Add(xAStartColorG);
                xEStartColor.Add(xAStartColorB);

                XElement xEEndColor = new XElement("endColor"); // ending color
                // emitterType element attributes
                XAttribute xAEndColorA = new XAttribute("A", endColor.A);
                XAttribute xAEndColorR = new XAttribute("R", endColor.R);
                XAttribute xAEndColorG = new XAttribute("G", endColor.G);
                XAttribute xAEndColorB = new XAttribute("B", endColor.B);
                // add attribute to emitterType
                xEEndColor.Add(xAEndColorA);
                xEEndColor.Add(xAEndColorR);
                xEEndColor.Add(xAEndColorG);
                xEEndColor.Add(xAEndColorB);

                XElement xEStartVelocity = new XElement("startVelocity"); // starting velocity
                // startVelocity attributes(x,y)
                XAttribute xAStartVelocityX = new XAttribute("X", startVelocity.X);
                XAttribute xAStartVelocityY = new XAttribute("Y", startVelocity.Y);

                // add attributes to startVelocity element
                xEStartVelocity.Add(xAStartVelocityX);
                xEStartVelocity.Add(xAStartVelocityY);

                XElement xEEndVelocity = new XElement("endVelocity"); // ending velocity
                // endVelocity attributes(x,y)

                XAttribute xAEndVelocityX = new XAttribute("X", endVelocity.X);
                XAttribute xAEndVelocityY = new XAttribute("Y", endVelocity.Y);

                // add attributes to startVelocity element
                xEEndVelocity.Add(xAEndVelocityX);
                xEEndVelocity.Add(xAEndVelocityY);

                XElement xEStartScale = new XElement("startScale"); // starting scale
                // startScale attributes(x,y)

                XAttribute xAStartScaleX = new XAttribute("X", startScale.X);
                XAttribute xAStartScaleY = new XAttribute("Y", startScale.Y);

                // add attributes to startVelocity element
                xEStartScale.Add(xAStartScaleX);
                xEStartScale.Add(xAStartScaleY);

                XElement xEEndScale = new XElement("endScale"); // ending scale
                // endScale attributes(x,y)

                XAttribute xAEndScaleX = new XAttribute("X", endScale.X);
                XAttribute xAEndScaleY = new XAttribute("Y", endScale.Y);

                // add attributes to EndScale element
                xEEndScale.Add(xAEndScaleX);
                xEEndScale.Add(xAEndScaleY);


                // add elements to the particle element
                xEParticle.Add(xEMaxParticleAge);
                xEParticle.Add(xEStartRotation);
                xEParticle.Add(xEEndRotation);
                xEParticle.Add(xEStartColor);
                xEParticle.Add(xEEndColor);

                xEParticle.Add(xEStartVelocity);
                xEParticle.Add(xEEndVelocity);
                xEParticle.Add(xEStartScale);
                xEParticle.Add(xEEndScale);

                // add particle element to the root element
                xERoot.Add(xEParticle);
                #endregion

                // save PXML file where desired
                xERoot.Save(dlg.FileName);

                // create an array of files currently in the save directory (won't save if already exists)
                string[] files = Directory.GetFiles(imageDir);

                // if the new image file is not in the current directory, save it
                if (files.Contains(imageDir + imageName) == false)
                    particleImage.Save(imageDir + imageName);
            }
        }

        // load from default XML file (startup)
        public Emitter LoadFromXML(string filename)
        {
            Emitter loadingEmitter = new Emitter();

                XElement xERoot = XElement.Load(imageDirPath + "\\..\\..\\ParticleFiles\\" + filename);

                XAttribute xALoop = xERoot.Attribute("isLooping"); // is the emitter looping
                loadingEmitter.isLooping = Convert.ToBoolean(xALoop.Value);
                XAttribute xAParticleImage = xERoot.Attribute("imageName"); // the path/location of the image
                loadingEmitter.imageName = Convert.ToString(xAParticleImage.Value);

                // emitter values
                #region
                XElement xEEmitter = xERoot.Element("Emitter");

                XElement xEType = xEEmitter.Element("emitterType");
                {
                    XAttribute xAType = xEType.Attribute("type");
                    loadingEmitter.emitType = Convert.ToInt32(xAType.Value);
                }

                XElement xENumParticles = xEEmitter.Element("numParticles");
                {
                    XAttribute xANumParticles = xENumParticles.Attribute("particles");
                    loadingEmitter.maxNumParticles = Convert.ToInt32(xANumParticles.Value);
                }

                XElement xELineRotation = xEEmitter.Element("lineRotation");
                {
                    XAttribute xALineRotation = xELineRotation.Attribute("rotation");
                    loadingEmitter.lineRotation = (float)Convert.ToDecimal(xALineRotation.Value);
                }

                XElement xESpawnRate = xEEmitter.Element("spawnRate");
                {
                    XAttribute xASpawnRate = xESpawnRate.Attribute("rate");
                    loadingEmitter.spawnRate = (float)Convert.ToDecimal(xASpawnRate.Value);
                }

                XElement xEPosition = xEEmitter.Element("position");
                {
                    XAttribute xAPositionX = xEPosition.Attribute("X");
                    loadingEmitter.position.X = (float)Convert.ToDecimal(xAPositionX.Value);
                    XAttribute xAPositionY = xEPosition.Attribute("Y");
                    loadingEmitter.position.Y = (float)Convert.ToDecimal(xAPositionY.Value);
                }

                XElement xECircleVector = xEEmitter.Element("circleVector");
                {
                    XAttribute xACircleVectorX = xECircleVector.Attribute("X");
                    loadingEmitter.circleVector.X = (float)Convert.ToDecimal(xACircleVectorX.Value);
                    XAttribute xACircleVectorY = xECircleVector.Attribute("Y");
                    loadingEmitter.circleVector.Y = (float)Convert.ToDecimal(xACircleVectorY.Value);
                }

                XElement xELineVector = xEEmitter.Element("lineVector");
                {
                    XAttribute xALineVectorX = xELineVector.Attribute("X");
                    loadingEmitter.lineVector.X = (float)Convert.ToDecimal(xALineVectorX.Value);
                    XAttribute xALineVectorY = xELineVector.Attribute("Y");
                    loadingEmitter.lineVector.Y = (float)Convert.ToDecimal(xALineVectorY.Value);
                }

                XElement xEEmitterRectSize = xEEmitter.Element("emitterRectSize");
                {
                    XAttribute xAEmitterRectSizeWidth = xEEmitterRectSize.Attribute("Width");
                    loadingEmitter.emitterRectSize.Width = Convert.ToInt32(xAEmitterRectSizeWidth.Value);
                    XAttribute xAEmitterRectSizeHeight = xEEmitterRectSize.Attribute("Height");
                    loadingEmitter.emitterRectSize.Height = Convert.ToInt32(xAEmitterRectSizeHeight.Value);
                }
                #endregion

                // particle values
                #region
                XElement xEParticle = xERoot.Element("Particle");

                XElement xEMaxParticleAge = xEParticle.Element("maxParticleAge"); // maxe particle age
                {
                    XAttribute xAMaxParticleAge = xEMaxParticleAge.Attribute("age");
                    loadingEmitter.maxParticleAge = (float)Convert.ToDecimal(xAMaxParticleAge.Value);
                }

                XElement xEStartRotation = xEParticle.Element("startRotation"); // starting rotation                
                {
                    XAttribute xAStartRotation = xEStartRotation.Attribute("rotation");
                    loadingEmitter.startRotation = (float)Convert.ToDecimal(xAStartRotation.Value);
                }

                XElement xEEndRotation = xEParticle.Element("endRotation"); // starting rotation
                {
                    XAttribute xAEndRotation = xEEndRotation.Attribute("rotation");
                    loadingEmitter.endRotation = (float)Convert.ToDecimal(xAEndRotation.Value);
                }

                XElement xEStartColor = xEParticle.Element("startColor"); // starting color               
                {
                    XAttribute xAStartColorA = xEStartColor.Attribute("A");
                    int A = Convert.ToInt32(xAStartColorA.Value);
                    XAttribute xAStartColorR = xEStartColor.Attribute("R");
                    int R = Convert.ToInt32(xAStartColorR.Value);
                    XAttribute xAStartColorG = xEStartColor.Attribute("G");
                    int G = Convert.ToInt32(xAStartColorG.Value);
                    XAttribute xAStartColorB = xEStartColor.Attribute("B");
                    int B = Convert.ToInt32(xAStartColorB.Value);

                    loadingEmitter.startColor = Color.FromArgb(A, R, G, B);
                }

                XElement xEEndColor = xEParticle.Element("endColor"); // ending color
                {
                    XAttribute xAEndColorA = xEEndColor.Attribute("A");
                    int A = Convert.ToInt32(xAEndColorA.Value);
                    XAttribute xAEndColorR = xEEndColor.Attribute("R");
                    int R = Convert.ToInt32(xAEndColorR.Value);
                    XAttribute xAEndColorG = xEEndColor.Attribute("G");
                    int G = Convert.ToInt32(xAEndColorG.Value);
                    XAttribute xAEndColorB = xEEndColor.Attribute("B");
                    int B = Convert.ToInt32(xAEndColorB.Value);

                    loadingEmitter.endColor = Color.FromArgb(A, R, G, B);
                }

                XElement xEStartVelocity = xEParticle.Element("startVelocity"); // starting velocity
                {
                    XAttribute xAStartVelocityX = xEStartVelocity.Attribute("X");
                    loadingEmitter.startVelocity.X = (float)Convert.ToDecimal(xAStartVelocityX.Value);
                    XAttribute xAStartVelocityY = xEStartVelocity.Attribute("Y");
                    loadingEmitter.startVelocity.Y = (float)Convert.ToDecimal(xAStartVelocityY.Value);
                }

                XElement xEEndVelocity = xEParticle.Element("endVelocity"); // ending velocity
                {
                    XAttribute xAEndVelocityX = xEEndVelocity.Attribute("X");
                    loadingEmitter.endVelocity.X = (float)Convert.ToDecimal(xAEndVelocityX.Value);
                    XAttribute xAEndVelocityY = xEEndVelocity.Attribute("Y");
                    loadingEmitter.endVelocity.Y = (float)Convert.ToDecimal(xAEndVelocityY.Value);
                }

                XElement xEStartScale = xEParticle.Element("startScale"); // starting scale
                {
                    XAttribute xAStartScaleX = xEStartScale.Attribute("X");
                    loadingEmitter.startScale.X = (float)Convert.ToDecimal(xAStartScaleX.Value);
                    XAttribute xAStartScaleY = xEStartScale.Attribute("Y");
                    loadingEmitter.startScale.Y = (float)Convert.ToDecimal(xAStartScaleY.Value);
                }
                XElement xEEndScale = xEParticle.Element("endScale"); // ending scale
                // endScale attributes(x,y)
                {
                    XAttribute xAEndScaleX = xEEndScale.Attribute("X");
                    loadingEmitter.endScale.X = (float)Convert.ToDecimal(xAEndScaleX.Value);
                    XAttribute xAEndScaleY = xEEndScale.Attribute("Y");
                    loadingEmitter.endScale.Y = (float)Convert.ToDecimal(xAEndScaleY.Value);
                }
                #endregion

            // create imageID
            loadingEmitter.imageID = TM.LoadTexture(imageDirPath + "\\" + loadingEmitter.imageName);
            // create bitmap image
            loadingEmitter.particleImage = new Bitmap(imageDirPath + "\\" + loadingEmitter.imageName);

            // return new Emitter
            return loadingEmitter;
        }

        // load from Saved XML file (open menu selection)
        public Emitter LoadFromXML()
        {
            Emitter loadingEmitter = new Emitter();

            OpenFileDialog dlg = new OpenFileDialog();
            dlg.Filter = "All Files(*.*)|*.*|Particle Files(*.pxml)|*.pxml";
            dlg.FilterIndex = 2;

            dlg.InitialDirectory = System.IO.Path.GetFullPath(System.IO.Directory.GetCurrentDirectory() + "\\..\\..\\resource\\ParticleFiles");

            if (DialogResult.OK == dlg.ShowDialog())
            {
                XElement xERoot = XElement.Load(dlg.FileName);

                XAttribute xALoop = xERoot.Attribute("isLooping"); // is the emitter looping
                loadingEmitter.isLooping = Convert.ToBoolean(xALoop.Value);
                XAttribute xAParticleImage = xERoot.Attribute("imageName"); // the path/location of the image
                loadingEmitter.imageName = Convert.ToString(xAParticleImage.Value);

                // emitter values
                #region
                XElement xEEmitter = xERoot.Element("Emitter");

                XElement xEType = xEEmitter.Element("emitterType");
                {
                    XAttribute xAType = xEType.Attribute("type");
                    loadingEmitter.emitType = Convert.ToInt32(xAType.Value);
                }

                XElement xENumParticles = xEEmitter.Element("numParticles");
                {
                    XAttribute xANumParticles = xENumParticles.Attribute("particles");
                    loadingEmitter.maxNumParticles = Convert.ToInt32(xANumParticles.Value);
                }

                XElement xELineRotation = xEEmitter.Element("lineRotation");
                {
                    XAttribute xALineRotation = xELineRotation.Attribute("rotation");
                    loadingEmitter.lineRotation = (float)Convert.ToDecimal(xALineRotation.Value);
                }

                XElement xESpawnRate = xEEmitter.Element("spawnRate");
                {
                    XAttribute xASpawnRate = xESpawnRate.Attribute("rate");
                    loadingEmitter.spawnRate = (float)Convert.ToDecimal(xASpawnRate.Value);
                }

                XElement xEPosition = xEEmitter.Element("position");
                {
                    XAttribute xAPositionX = xEPosition.Attribute("X");
                    loadingEmitter.position.X = (float)Convert.ToDecimal(xAPositionX.Value);
                    XAttribute xAPositionY = xEPosition.Attribute("Y");
                    loadingEmitter.position.Y = (float)Convert.ToDecimal(xAPositionY.Value);
                }

                XElement xECircleVector = xEEmitter.Element("circleVector");
                {
                    XAttribute xACircleVectorX = xECircleVector.Attribute("X");
                    loadingEmitter.circleVector.X = (float)Convert.ToDecimal(xACircleVectorX.Value);
                    XAttribute xACircleVectorY = xECircleVector.Attribute("Y");
                    loadingEmitter.circleVector.Y = (float)Convert.ToDecimal(xACircleVectorY.Value);
                }

                XElement xELineVector = xEEmitter.Element("lineVector");
                {
                    XAttribute xALineVectorX = xELineVector.Attribute("X");
                    loadingEmitter.lineVector.X = (float)Convert.ToDecimal(xALineVectorX.Value);
                    XAttribute xALineVectorY = xELineVector.Attribute("Y");
                    loadingEmitter.lineVector.Y = (float)Convert.ToDecimal(xALineVectorY.Value);
                }

                XElement xEEmitterRectSize = xEEmitter.Element("emitterRectSize");
                {
                    XAttribute xAEmitterRectSizeWidth = xEEmitterRectSize.Attribute("Width");
                    loadingEmitter.emitterRectSize.Width = Convert.ToInt32(xAEmitterRectSizeWidth.Value);
                    XAttribute xAEmitterRectSizeHeight = xEEmitterRectSize.Attribute("Height");
                    loadingEmitter.emitterRectSize.Height = Convert.ToInt32(xAEmitterRectSizeHeight.Value);
                }
                #endregion

                // particle values
                #region
                XElement xEParticle = xERoot.Element("Particle");

                XElement xEMaxParticleAge = xEParticle.Element("maxParticleAge"); // maxe particle age
                {
                    XAttribute xAMaxParticleAge = xEMaxParticleAge.Attribute("age");
                    loadingEmitter.maxParticleAge = (float)Convert.ToDecimal(xAMaxParticleAge.Value);
                }

                XElement xEStartRotation = xEParticle.Element("startRotation"); // starting rotation                
                {
                    XAttribute xAStartRotation = xEStartRotation.Attribute("rotation");
                    loadingEmitter.startRotation = (float)Convert.ToDecimal(xAStartRotation.Value);
                }

                XElement xEEndRotation = xEParticle.Element("endRotation"); // starting rotation
                {
                    XAttribute xAEndRotation = xEEndRotation.Attribute("rotation");
                    loadingEmitter.endRotation = (float)Convert.ToDecimal(xAEndRotation.Value);
                }

                XElement xEStartColor = xEParticle.Element("startColor"); // starting color               
                {
                    XAttribute xAStartColorA = xEStartColor.Attribute("A");
                    int A = Convert.ToInt32(xAStartColorA.Value);
                    XAttribute xAStartColorR = xEStartColor.Attribute("R");
                    int R = Convert.ToInt32(xAStartColorR.Value);
                    XAttribute xAStartColorG = xEStartColor.Attribute("G");
                    int G = Convert.ToInt32(xAStartColorG.Value);
                    XAttribute xAStartColorB = xEStartColor.Attribute("B");
                    int B = Convert.ToInt32(xAStartColorB.Value);

                    loadingEmitter.startColor = Color.FromArgb(A, R, G, B);
                }

                XElement xEEndColor = xEParticle.Element("endColor"); // ending color
                {
                    XAttribute xAEndColorA = xEEndColor.Attribute("A");
                    int A = Convert.ToInt32(xAEndColorA.Value);
                    XAttribute xAEndColorR = xEEndColor.Attribute("R");
                    int R = Convert.ToInt32(xAEndColorR.Value);
                    XAttribute xAEndColorG = xEEndColor.Attribute("G");
                    int G = Convert.ToInt32(xAEndColorG.Value);
                    XAttribute xAEndColorB = xEEndColor.Attribute("B");
                    int B = Convert.ToInt32(xAEndColorB.Value);

                    loadingEmitter.endColor = Color.FromArgb(A, R, G, B);
                }

                XElement xEStartVelocity = xEParticle.Element("startVelocity"); // starting velocity
                {
                    XAttribute xAStartVelocityX = xEStartVelocity.Attribute("X");
                    loadingEmitter.startVelocity.X = (float)Convert.ToDecimal(xAStartVelocityX.Value);
                    XAttribute xAStartVelocityY = xEStartVelocity.Attribute("Y");
                    loadingEmitter.startVelocity.Y = (float)Convert.ToDecimal(xAStartVelocityY.Value);
                }

                XElement xEEndVelocity = xEParticle.Element("endVelocity"); // ending velocity
                {
                    XAttribute xAEndVelocityX = xEEndVelocity.Attribute("X");
                    loadingEmitter.endVelocity.X = (float)Convert.ToDecimal(xAEndVelocityX.Value);
                    XAttribute xAEndVelocityY = xEEndVelocity.Attribute("Y");
                    loadingEmitter.endVelocity.Y = (float)Convert.ToDecimal(xAEndVelocityY.Value);
                }

                XElement xEStartScale = xEParticle.Element("startScale"); // starting scale
                {
                    XAttribute xAStartScaleX = xEStartScale.Attribute("X");
                    loadingEmitter.startScale.X = (float)Convert.ToDecimal(xAStartScaleX.Value);
                    XAttribute xAStartScaleY = xEStartScale.Attribute("Y");
                    loadingEmitter.startScale.Y = (float)Convert.ToDecimal(xAStartScaleY.Value);
                }
                XElement xEEndScale = xEParticle.Element("endScale"); // ending scale
                // endScale attributes(x,y)
                {
                    XAttribute xAEndScaleX = xEEndScale.Attribute("X");
                    loadingEmitter.endScale.X = (float)Convert.ToDecimal(xAEndScaleX.Value);
                    XAttribute xAEndScaleY = xEEndScale.Attribute("Y");
                    loadingEmitter.endScale.Y = (float)Convert.ToDecimal(xAEndScaleY.Value);
                }
                #endregion
            }

            // create imageID
            loadingEmitter.imageID = TM.LoadTexture(imageDirPath + "\\" + loadingEmitter.imageName);
            // create bitmap image
            loadingEmitter.particleImage = new Bitmap(imageDirPath + "\\" + loadingEmitter.imageName);

            // return new Emitter
            return loadingEmitter;
        }

        // Update the emitter
        public void Update(float elapsedTime)
        {
            // keep particles from following the emitter when it moves
            #region
            // keep particles from following the emitter when it moves on the X-axis
            if (moveDirectionX1 == moveDirectionX2 && moveDirectionXTimer > 0 && moveDirectionX1 != 0)
            {
                moveDirectionXTimer -= elapsedTime;
            }
            else if (moveDirectionX1 == moveDirectionX2 && moveDirectionXTimer < 0)
            {
                moveDirectionXTimer = .2f;
                moveDirectionX1 = moveDirectionX2 = 0;
            }
            else if (moveDirectionX1 != moveDirectionX2)
                moveDirectionX2 = moveDirectionX1;

            // keep particles from following the emitter when it moves on the Y-axis
            if (moveDirectionY1 == moveDirectionY2 && moveDirectionYTimer > 0 && moveDirectionY1 != 0)
            {
                moveDirectionYTimer -= elapsedTime;
            }
            else if (moveDirectionY1 == moveDirectionY2 && moveDirectionYTimer < 0)
            {
                moveDirectionYTimer = .2f;
                moveDirectionY1 = moveDirectionY2 = 0;
            }
            else if (moveDirectionY1 != moveDirectionY2)
                moveDirectionY2 = moveDirectionY1;
            #endregion

            // not looping = burst
            if (!isLooping)
            {
                for (int i = particleList.Count(); i < maxNumParticles; i++)
                    particleList.Add(Respawn(new Particle(this)));
            }

            // if max number of particles was increased, add more to the list
            if (particleList.Count < maxNumParticles)
                particleList.Add(Respawn(new Particle(this)));

            if (particleList.Count > maxNumParticles)
                particleList.Clear();

            // run spawnTimer
            if (spawnTimer >= 0)
                spawnTimer -= elapsedTime;

            // For each particle in particleList
            for (int i = 0; i < particleList.Count(); i++)
            {
                // deactivate particle if dead (will deactivate ALL dead)
                if (particleList[i].currAge > particleList[i].maxAge && particleList[i].isActive)
                {
                    // deactivate the particle (so it wont render)
                    particleList[i].isActive = false;
                    // reduce the count of active particles
                    activeCount--;
                }

                // update each live particle
                if (particleList[i].isActive)
                    particleList[i].Update(elapsedTime);

                // respawn an inactive particle (will respawn ONE particle - see Respawn)
                if (particleList[i].isActive == false && spawnTimer < 0 && activeCount < maxNumParticles && isLooping)
                {
                    // run Respawn() and replace old particle with new one
                    particleList[i] = Respawn(particleList[i]);
                    // increase number of active particles
                    activeCount++;
                }
            }
        }

        // display the particles
        public void Render(Panel renderPanel)
        {
            // reset background color
            DX.Clear(renderPanel, Color.White);

            DX.DeviceBegin();
            DX.SpriteBegin();

            if (particleList != null)
            {
                // search the emitters particleList
                for (int i = 0; i < particleList.Count; i++)
                {
                    // if particle[i] isActive...
                    if (particleList[i].isActive)
                    {
                        // used for code reduction and simplicity
                        float scaleX = particleList[i].currScale.X;
                        float scaleY = particleList[i].currScale.Y;

                        // offset position by image size
                        Vector2 tempPosition = particleList[i].position - new Vector2(TM.GetTextureWidth(imageID) / 2 * scaleX, TM.GetTextureHeight(imageID) / 2 * scaleY);

                        // draw the image
                        TM.Draw(
                            imageID, // what image to use
                            (int)tempPosition.X, (int)tempPosition.Y, // where to draw the image
                            scaleX, scaleY, // what scale to use
                            Rectangle.Empty, // render the whole image (not part of it)
                            TM.GetTextureWidth(imageID) / 2 * scaleX, TM.GetTextureHeight(imageID) / 2 * scaleY, // center of image for rotation
                            particleList[i].currRotation, // amount of rotation
                            particleList[i].currColor); // color to display with
                    }
                }
            }

            DX.SpriteEnd();
            DX.DeviceEnd();
            DX.Present();
        }

        // Respawn a particle
        public Particle Respawn(Particle who)
        {
            // create a temporary particle to modify
            Particle tempParticle = who;

            // reset the timer (keeps Update from respawning multiple particles)
            spawnTimer = spawnRate;

            // create temp variable for particle location
            Vector2 tempParticleLocation = position;
            // create temp variable for particle velocity
            Vector2 tempVel = startVelocity;

            // switch between emitter types
            switch (emitType)
            {
                #region
                case 0: // point
                    // nothing here, tempRectLocation = position (already set)
                    break;
                case 1: // rectangle
                    {
                        #region
                        // create a temp rect from xml / default values
                        Rectangle tempRect = new Rectangle(
                           (int)position.X - emitterRectSize.Width / 2,
                           (int)position.Y - emitterRectSize.Height / 2,
                           emitterRectSize.Width,
                           emitterRectSize.Height
                           );

                        // set a random spawn point within the temp rect
                        tempParticleLocation = new Vector2(
                            ness.Next(tempRect.Left, tempRect.Right),
                            ness.Next(tempRect.Top, tempRect.Bottom)
                            );
                        #endregion
                    }
                    break;
                case 2: // circle
                    {
                        #region
                        // create a 2D offSet vector for radius
                        Vector2 offSet = circleVector;

                        // create a 3D vector to rotate the current 2D vector
                        Vector3 tempV3 = new Vector3(offSet.X, offSet.Y, 0);

                        // random angle (in degrees)
                        float randDegree = ness.Next(360);
                        // convert from degrees to radians
                        float radians = randDegree * (float)(Math.PI / 180);

                        // create a rotation matrix using random radian angle
                        Matrix rotate = Matrix.RotationZ(radians);

                        // rotate the 3D vector
                        tempV3.TransformCoordinate(rotate);
                        // convert the 3D vector to 2D
                        offSet = new Vector2(tempV3.X, tempV3.Y);

                        // randomize the offSets position on the line (radius)
                        offSet.Scale((float)ness.NextDouble());

                        // offset the particles spawn position
                        tempParticleLocation += offSet;
                        #endregion
                    }
                    break;
                case 3: // line
                    {
                        #region
                        // create an offSet vector for radius
                        Vector2 offSet = lineVector;

                        // create a 3D vector to rotate the current 2D vector
                        Vector3 tempV3 = new Vector3(offSet.X, offSet.Y, 0);

                        // create a rotation matrix using current lineRotation input
                        Matrix rotate = Matrix.RotationZ(lineRotation * ((float)Math.PI / 180));

                        // randomize pos / neg results (simulates 360 degrees, ie.. a circle)
                        //tempV3 *= ness.NextDouble() < .5f ? -1 : 1;

                        // rotate the 3D vector
                        tempV3.TransformCoordinate(rotate);
                        // convert the 3D vector to a 2D vector
                        offSet = new Vector2(tempV3.X, tempV3.Y);

                        // randomize the offSets position on the line
                        offSet.Scale((float)ness.NextDouble());

                        // offset the particles spawn position
                        tempParticleLocation += offSet;
                        #endregion
                    }
                    break;
                #endregion
            }

            // reset particle variables
            {
                #region

                // create tempParticle age and randomize it from the original
                float tempParticleAge = (float)(ness.NextDouble() * maxParticleAge);

                // randomize tempVelocity within startVelocity Range
                tempVel = new Vector2(ness.Next((int)startVelocity.X), ness.Next((int)startVelocity.Y));

                // create velocityOffset temp variable
                Vector2 velOffset = tempVel;

                // create a 3D vector to rotate the current 2D vector
                Vector3 tempV3 = new Vector3(velOffset.X, velOffset.Y, 0);

                // random angle (in degrees)
                float randDegree = ness.Next(360);
                // convert from degrees to radians
                float radians = randDegree * (float)(Math.PI / 180);

                // create a rotation matrix using random radian angle
                Matrix rotate = Matrix.RotationZ(radians);

                // rotate the 3D vector
                tempV3.TransformCoordinate(rotate);
                // convert the 3D vector to 2D
                velOffset = new Vector2(tempV3.X, tempV3.Y);

                // offset the particles spawn position
                tempVel = velOffset;

                // create a 2D offSet vector for radius
                velOffset = endVelocity;

                // create a 3D vector to rotate the current 2D vector
                tempV3 = new Vector3(velOffset.X, velOffset.Y, 0);

                // create a rotation matrix using random radian angle
                rotate = Matrix.RotationZ(radians);

                // rotate the 3D vector
                tempV3.TransformCoordinate(rotate);
                // convert the 3D vector to 2D
                velOffset = new Vector2(tempV3.X, tempV3.Y);

                Vector2 tempEndVel = velOffset;

                // keep particles from "crossing over" emitter (especially with rectangle and circle emitter types)
                #region
                if (tempParticleLocation.X < position.X && tempVel.X > 0)
                    tempVel.X = -tempVel.X;
                if (tempParticleLocation.X > position.X && tempVel.X < 0)
                    tempVel.X = -tempVel.X;
                if (tempParticleLocation.Y < position.Y && tempVel.Y > 0)
                    tempVel.Y = -tempVel.Y;
                if (tempParticleLocation.Y > position.Y && tempVel.Y < 0)
                    tempVel.Y = -tempVel.Y;
                #endregion

                // re-assign new variables (must set since reactivating not creating NEW)
                #region
                // BOOL
                tempParticle.isActive = true; // reactivate the particle

                // FLOAT
                tempParticle.maxAge = tempParticleAge; // reset maxAge
                tempParticle.currAge = 0; // restart current age

                tempParticle.startRotation = startRotation; // reset startRotation
                tempParticle.currRotation = startRotation; // reset currRotation
                tempParticle.endRotation = endRotation; // reset endRotation
                tempParticle.rotationReducer = startRotation; // reset rotation reducer

                tempParticle.diffA = endColor.A - startColor.A; // reset difference between newest Alpha colors
                tempParticle.diffR = endColor.R - startColor.R; // reset difference between newest Red colors
                tempParticle.diffG = endColor.G - startColor.G; // reset difference between newest Green colors
                tempParticle.diffB = endColor.B - startColor.B; // reset difference between newest Blue colors

                tempParticle.colorReducerA = 0; // reset Alpha reducer
                tempParticle.colorReducerR = 0; // reset Red reducer
                tempParticle.colorReducerG = 0; // reset Green reducer
                tempParticle.colorReducerB = 0; // resest Blue reducer

                // VECTOR2
                tempParticle.position = tempParticleLocation; // new position based on emitter type

                tempParticle.startVelocity = tempVel; // reset startVelocity to newest value
                tempParticle.currVelocity = tempVel; // new random velocity
                tempParticle.endVelocity = tempEndVel; // reset endVelocity to newest value
                tempParticle.velocityReducer = new Vector2(0, 0); // reset velocityReducer to newest value

                tempParticle.startScale = startScale; // reset startScale to newest value
                tempParticle.currScale = startScale; // reset currScale
                tempParticle.endScale = endScale; // reset endScale to newest value
                tempParticle.scaleReducer = new Vector2(0, 0); // reset scaleReducer to newest value

                tempParticle.startColor = startColor; // reset startColor to newest value
                tempParticle.currColor = startColor; // reset current color
                tempParticle.endColor = endColor; // reset endColor to newest value
                tempParticle.currA = startColor.A; // reset current Alpha color
                tempParticle.currR = startColor.R; // reset current Red color
                tempParticle.currG = startColor.G; // reset current Green color
                tempParticle.currB = startColor.B; // reset current Blue color
                #endregion

                #endregion
            }

            // return the new particle
            return tempParticle;
        }
    }
}